<template>
  <div>
    <el-dialog title="依赖管理" :visible.sync="showDialog" :before-close="closeDialog">
      <el-row v-if="!isLoadingInstalledPackages" :gutter="30">
        <!--选择依赖-->
        <div v-if="tab_value===1">
          <el-col :span="10">
            <div class="column-title ml-10">依赖选择</div>
            <el-table :data="searchedPackages" height="46vh" stripe>
              <el-table-column label="包名" prop="name" width="75px" show-overflow-tooltip />
              <el-table-column label="版本" prop="version" align="center" style="text-align: center;">
                <template slot-scope="scope">
                  <div>
                    <span style="margin-right: 10px">{{ scope.row.version }}</span>
                    <el-dropdown v-if="scope.row.all_version.length>1 && !isPackageCmpTrue(scope.row.name, installed)" trigger="click">
                      <span class="el-dropdown-link">
                        <i class="el-icon-more" />
                      </span>
                      <el-dropdown-menu slot="dropdown">
                        <el-dropdown-item
                          v-for="item in scope.row.all_version"
                          :key="item"
                          @click.native="updatePackageVersion(item, scope.row)"
                        >{{ item }}</el-dropdown-item>
                      </el-dropdown-menu>
                    </el-dropdown>
                  </div>
                </template>
              </el-table-column>
              <el-table-column align="right">
                <template #header>
                  <el-input v-model="searchInput" size="mini" placeholder="输入关键字搜索" />
                </template>
                <template slot-scope="scope">
                  <el-tag v-if="isPackageCmpTrue(scope.row.name, installed)" type="success" effect="plain">
                    已安装
                  </el-tag>
                  <el-button
                    v-else-if="isPackageCmpTrue(scope.row.name, selectedAdd) === false"
                    size="mini"
                    :disabled="isPackageCmpTrue(scope.row.name, installed)"
                    @click="addPackage(scope.row.name, scope.row.version)"
                  >
                    添加
                  </el-button>
                  <el-button v-else size="mini" type="danger" @click="cancelAdd(scope.row.name)">
                    取消
                  </el-button>
                </template>
              </el-table-column>
            </el-table>
            <div class="text-center mt-20">
              <el-pagination background layout="prev, pager, next" :pager-count="5" :current-page="pageComponent.page" :page-size="pageComponent.pageSize" :total="pageComponent.total" @current-change="goPage" />
            </div>
          </el-col>
          <!--已安装-->
          <el-col :span="8">
            <div>
              <div class="ml-10 column-title">已安装 {{ installed.length }} 个依赖</div>
              <el-table :data="installed" height="50vh" stripe>
                <el-table-column label="包名" prop="name" show-overflow-tooltip />
                <el-table-column label="版本" prop="version" align="right" />
                <el-table-column align="right">
                  <template slot="header">
                    操作
                  </template>
                  <template slot-scope="scope">
                    <el-button
                      v-if="isPackageCmpTrue(scope.row.name, selectedDelete) === false"
                      :disabled="isPackageCmpTrue(scope.row.name, userInstalled)===false"
                      size="mini"
                      @click="deletePackage(scope.row.name, scope.row.version)"
                    >
                      删除
                    </el-button>
                    <el-button
                      v-else
                      size="mini"
                      type="danger"
                      @click="cancelDelete(scope.row.name)"
                    >
                      取消
                    </el-button>
                  </template>
                </el-table-column>
              </el-table>
            </div>
          </el-col>
          <!--待安装-->
          <el-col :span="6">
            <div class="dis-flex space-between flex-column">
              <div class="column-title">待安装 {{ selectedAdd.length }} 个依赖</div>
              <div class="mt-10 list">
                <div v-if="selectedAdd.length > 0">
                  <div v-for="item in selectedAdd" :key="item" class="selectedAdd">
                    <span> {{ item.name+'=='+item.version }} </span>
                  </div>
                </div>
                <div v-else>暂⽆选择</div>
              </div>
              <el-divider />
              <div class="column-title">待删除 {{ selectedDelete.length }} 个依赖</div>
              <div class="mt-10 list">
                <div v-if="selectedDelete.length > 0">
                  <div v-for="item in selectedDelete" :key="item.name" class="selectedAdd">
                    <span> {{ item.name+'=='+item.version }} </span>
                  </div>
                </div>
                <div v-else>暂⽆选择</div>
              </div>
            </div>
          </el-col>
        </div>
        <div v-else-if="tab_value===2">
          <el-table :data="publicLayer" height="500px" stripe>
            <el-table-column label="基础模板" prop="name" align="center" width="250px" />
            <el-table-column label="详情" type="expand" align="left">
              <template #default="props">
                <div class="display-window">
                  此基础库将包含以下依赖:
                  {{ props.row.contains }}
                </div>
              </template>
            </el-table-column>
            <el-table-column label="操作" align="center">
              <template slot-scope="scope">
                <el-button
                  size="mini"
                  :disabled="selectPublicLayer !== '' && selectPublicLayer !== scope.row.name"
                  @click="projectSelectPublicLayer(scope.row.name, scope.row.name !== selectPublicLayer)"
                >
                  <div v-if="scope.row.name !== selectPublicLayer">
                    选择并应用
                  </div>
                  <div v-else>
                    取消应用
                  </div>
                </el-button>
              </template>
            </el-table-column>
          </el-table>
        </div>
        <div v-else>
          <div class="editor-tab">
            <editor
              v-model="requirementFile.editContent"
              class="editor"
              :options="editorOptions"
              theme="chrome"
              width="100%"
              lang="python"
              @init="editorInit"
              @input="(event) => { requirementFile.editContent = event; }"
            />
          </div>
        </div>
      </el-row>
      <el-skeleton v-else :rows="15" animated />
      <el-dialog
        title="安装进度"
        :visible.sync="realTimeUpdateLog"
        width="40%"
        center
        destroy-on-close
        append-to-body
      >
        <pre
          id="realLogText"
          v-loading="realTimeLog === ''"
          class="function-view-log h-max"
          style="padding-left: 10px;"
        >{{ realTimeLog }}</pre>
      </el-dialog>
      <el-dialog title="更新日志" :visible.sync="showLogInformation" width="40%" center destroy-on-close append-to-body>
        <pre
          id="logInformationText"
          class="function-view-log h-max"
          style="padding-left: 10px;"
        >{{ logInformation }}</pre>
      </el-dialog>
      <div slot="footer" class="dialog-footer">
        <div class="button-container">
          <el-button
            :disabled="selectedAdd.length === 0 && selectedDelete.length === 0"
            :loading="isUpdating"
            size="mini"
            style="background: #ffa54f; color: white; margin-right: 10px;"
            :class="{'Disabled': selectedAdd.length === 0 && selectedDelete.length === 0 }"
            @click="updateDependency"
          >
            更新依赖
          </el-button>
          <el-button
            :disabled="isDownloading === false"
            size="mini"
            style="background: #ffa54f; color: white; margin-right: 10px;"
            :class="{'Disabled': isDownloading === false}"
            @click="realTimeUpdateLog = true"
          >
            安装进度
          </el-button>
          <el-button
            :disabled="isDownloading === true || logInformation === ''"
            size="mini"
            style="background: #ffa54f; color: white; margin-right: 10px;"
            :class="{'Disabled': isDownloading === true || logInformation === ''}"
            @click="showLogInformation = true"
          >
            安装日志
          </el-button>
          <el-button
            size="mini"
            style="background: #ffa54f; color: white; margin-right: 10px;"
            :disabled="tab_value===2"
            :class="{'Disabled': tab_value===2 }"
            @click="tab_value = tab_value!==3 ? 3 : 1"
          >
            <div v-if="tab_value===1 || tab_value===2">模式切换</div>
            <div v-else-if="tab_value===3">回主界面</div>
          </el-button>
          <el-button
            size="mini"
            style="background: #ffa54f; color: white; margin-right: 10px;"
            :disabled="tab_value===3"
            :class="{'Disabled': tab_value===3 }"
            @click="tab_value = tab_value!==2 ? 2 : 1"
          >
            <div v-if="tab_value===1 || tab_value===3">公共模板</div>
            <div v-else-if="tab_value===2">回主界面</div>
          </el-button>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { searchRequirements, getLayerDependencyForProject, createLayerForProject } from '@/api/userProject';
import { getObjectUrl } from '@/utils/aliOss';
import editor from 'vue2-ace-editor';
import { downloadOss } from '@/api/userProject';
import { getPublicLayerForLibrary } from '@/api/userProjectLibrary';

export default {
  components: {
    editor
  },
  props: {
    showDialog: { type: Boolean, default: false },
    projectId: { type: String, required: true }
  },
  data() {
    return {
      isLoadingInstalledPackages: false,
      isUpdating: false,
      pageComponent: {
        page: 0,
        pageSize: 8,
        total: 0
      },
      editorOptions: {
        enableBasicAutocompletion: true,
        enableSnippets: true,
        enableLiveAutocompletion: true,
        tabSize: 2,
        fontSize: 15,
        scrollbar: true,
        showPrintMargin: false // 去除编辑器里的竖线
      },
      requirementFile: {},
      searchedPackages: [],
      installed: [],
      searchInput: '',
      selectedAdd: [],
      selectedDelete: [],
      isDownloading: false,
      realTimeUpdateLog: false,
      realTimeLog: '',
      tab_value: 1,
      logInformation: '',
      showLogInformation: false,
      publicLayer: [],
      selectPublicLayer: '',
      userInstalled: [],
      layerInstalled: []
    };
  },
  watch: {
    searchInput: function(newSearch) {
      this.getRequirements(newSearch, this.pageComponent.pageSize, (this.pageComponent.page - 1) * this.pageComponent.pageSize);
    },
    realTimeLog: function() {
      this.$nextTick(() => {
        const textarea = document.getElementById('realLogText');
        textarea.scrollTop = textarea.scrollHeight;
      });
    },
    realTimeUpdateLog: function() {
      var interval;
      if (this.realTimeUpdateLog === true) {
        this.realTimeLog = '';
        const projectName = this.$props.projectId.substring(8, 17) + `/` + this.$props.projectId.substring(18);
        const name = `projectLayer/` + projectName + `/progress.txt`;
        const url = getObjectUrl(name);
        interval = setInterval(() => {
          url
            .then((url) => {
              downloadOss(url)
                .then((resp) => {
                  resp.text().then((text) => {
                    this.realTimeLog = text;
                    if (/please wait$/g.test(text)) {
                      this.isDownloading = false;
                      clearInterval(interval);
                    }
                  });
                });
            });
        }, 2000);
      } else if (this.realTimeUpdateLog === false) {
        // this.isDownloading = false;
        if (interval) clearInterval(interval);
      }
    },
    projectId: function() {
      this.isLoadingInstalledPackages = true;
      this.userInstalled = [];
      this.layerInstalled = [];
      getLayerDependencyForProject(this.$props.projectId).then((res) => {
        this.userInstalled = JSON.parse(res.PackagesJson);
      }).catch(() => {
        this.userInstalled = [];
      }).finally(() => {
        this.isLoadingInstalledPackages = false;
        if (this.projectId in this.$store.state.matlab.projectPublicLayer) {
          this.selectPublicLayer = this.$store.state.matlab.projectPublicLayer[this.projectId].name;
        } else {
          this.selectPublicLayer = '';
        }
        if (this.selectPublicLayer !== '') {
          const publicLayer = this.publicLayer.filter((x) => this.selectPublicLayer === x.name);
          const layerList = publicLayer[0].contains.split(',');
          for (var i = 0; i < layerList.length; i++) {
            const splitResult = layerList[i].split('==');
            this.layerInstalled.push({ name: splitResult[0], version: splitResult[1] });
          }
        }
        this.installed = this.userInstalled.concat(this.layerInstalled);
      });
    }
  },
  created() {
    this.getRequirements('', 8, 0);
    this.isLoadingInstalledPackages = true;
    this.requirementFile.editContent = '# -*- coding: UTF-8 -*-\n' +
      '# 可在本文件中写入依赖信息\n' +
      '# 比如: cycler==0.10.0\n' +
      '# 填好信息后点击右上角的更新依赖即可为函数拉取依赖\n';
    getPublicLayerForLibrary().then((res) => {
      const data = [];
      let i;
      for (i = 0; i < res.Data.Names.length; i++) {
        data.push({ name: res.Data.Names[i], arn: res.Data.Arn[i], contains: res.Data.Contains[i] });
      }
      this.publicLayer = data;
    });
  },
  methods: {
    // 关闭对话框
    closeDialog() {
      this.$emit('closeDialog');
    },
    // 搜索依赖
    getRequirements(name, limit, offset) {
      searchRequirements({ name, limit, offset }).then((resp) => {
        const { total, names, lastest_version, all_versions } = resp;
        this.pageComponent.total = total;
        if (names?.length) {
          const data = [];
          let i;
          for (i = 0; i < names.length; i++) {
            data.push({ name: names[i], version: lastest_version[i], all_version: all_versions[i].replaceAll(',', '').split(' ') });
          }
          this.searchedPackages = data;
        }
      });
    },
    // 使用下拉式窗口更新版本
    updatePackageVersion(version, obj) {
      obj.version = version;
      if (this.isPackageCmpTrue(obj.name, this.selectedAdd)) {
        this.cancelAdd(obj.name);
        this.addPackage(obj.name, obj.version);
      }
    },
    // 使用公共层
    projectSelectPublicLayer(name, ifSelect) {
      if (ifSelect) {
        this.$confirm('将要使用新的AI公共依赖包？', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          this.selectPublicLayer = name;
          const publicLayer = this.publicLayer.filter((x) => name === x.name);
          const layerList = publicLayer[0].contains.split(',');
          for (var i = 0; i < layerList.length; i++) {
            const splitResult = layerList[i].split('==');
            this.layerInstalled.push({ name: splitResult[0], version: splitResult[1] });
          }
          this.installed = this.userInstalled.concat(this.layerInstalled);
          this.$store.state.matlab.projectPublicLayer[this.projectId] = { name: this.selectPublicLayer, arn: publicLayer[0].arn };
        });
      } else {
        this.selectPublicLayer = '';
        this.$store.state.functions.usePublicLayers = '';
        this.layerInstalled = [];
        this.installed = this.userInstalled;
        delete this.$store.state.matlab.projectPublicLayer[this.projectId];
      }
    },
    // 更新依赖
    updateDependency() {
      this.isUpdating = true;
      // 合并已安装 将要删除 将要添加
      const installed = [];
      this.userInstalled.forEach((item) => installed.push(item));
      const arr = installed.filter((x) => !this.selectedDelete.some((item) => x.name === item.name));
      // 这个地方是根据对应的option来对不同界面下的requirements进行更新的。
      let requirementsString = '';
      if (this.tab_value === 3) {
        requirementsString = this.requirementFile.editContent.trim() + '\n';
        this.installed.forEach((item) => {
          requirementsString += item.name + '==' + item.version + '\n';
        });
      } else {
        arr.forEach((item) => {
          requirementsString += item.name + '==' + item.version + '\n';
        });
        this.selectedAdd.forEach((item) => {
          requirementsString += item.name + '==' + item.version + '\n';
        });
      }
      requirementsString = requirementsString.trim() + '\n';
      this.isDownloading = true;
      createLayerForProject(this.$props.projectId, requirementsString).then((res) => {
        this.selectedAdd = [];
        this.selectedDelete = [];
        this.isUpdating = false;
        this.isLoadingInstalledPackages = true;
        this.isDownloading = false;
        this.realTimeUpdateLog = false;
        this.logInformation = res.Rmsg;
        getLayerDependencyForProject(this.$props.projectId).then((res) => {
          this.userInstalled = JSON.parse(res.PackagesJson);
        }).catch(() => {
          this.userInstalled = [];
        }).finally(() => {
          this.isLoadingInstalledPackages = false;
          this.requirementFile.editContent = '# -*- coding: UTF-8 -*-\n' +
            '# 可在本文件中写入依赖信息\n' +
            '# 比如: cycler==0.10.0\n' +
            '# 填好信息后点击右上角的更新依赖即可为函数拉取依赖\n';
          this.installed = this.userInstalled.concat(this.layerInstalled);
        });
      });
    },
    // 跳转
    goPage(val) {
      this.pageComponent.page = val;
      this.getRequirements(this.searchInput, this.pageComponent.pageSize, (this.pageComponent.page - 1) * this.pageComponent.pageSize);
    },
    isPackageCmpTrue(name, cmpList) {
      for (const p of cmpList) {
        if (p.name === name) {
          return true;
        }
      }
      return false;
    },

    // 添加package
    addPackage(name, version) {
      // 其实应该是添加name与version了 this.selectAdd.push(name, version);
      this.selectedAdd.push({ name, version });
    },
    // 取消添加package
    cancelAdd(name) {
      this.selectedAdd = this.selectedAdd.filter((x) => x.name !== name);
    },
    deletePackage(name, version) {
      this.selectedDelete.push({ name, version });
    },
    cancelDelete(name) {
      this.selectedDelete = this.selectedDelete.filter((x) => x.name !== name);
    },
    editorInit() {
      require('brace/ext/language_tools');
      require('brace/mode/python');
      require('brace/theme/chrome');
      require('brace/mode/less');
      require('brace/snippets/python');
    }
  }
};

</script>

<style lang="scss" scoped>
.el-table__body-wrapper::-webkit-scrollbar {
  width: 5px;
}
.el-table__body-wrapper::-webkit-scrollbar-thumb {
  background-color:dimgray;
  border-radius: 3px;
}
.column-title {
  font-weight: 550;
  font-size: 15px;
  color: #7f7f7f;
}
.Disabled {
  opacity: 0.6;
}
.list {
  height: 20vh;
  overflow: auto;
}
.list::-webkit-scrollbar {
  width: 5px;
}
.list::-webkit-scrollbar-thumb {
  background-color:dimgray;
  border-radius: 3px;
}
.button-container {
  display: flex;
  flex-direction: row;
}
.editor-tab {
  display: flex;
  flex-direction: column;
  height: 50vh;
  width: 100%;
  flex: 1;
  margin-bottom: 15px;
  .editor {
    height: 45vh;
    border-bottom: 1px solid #d5d5d5;
  }
}
.function-view-log {
  height: 300px;
  overflow: auto;
  background-color: #263238;
  white-space: pre-wrap;
  line-height: 18px;
  font-family: Consolas,Menlo,Courier,monospace,-apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif;
  font-size: 14px;
  font-variant-ligatures: contextual;
  -webkit-font-smoothing: antialiased;
  color: #eff;
}
.display-window {
  margin-right: 10px;
  margin-bottom: 10px;
  margin-left: 10px;
  font-weight: bolder;
  background:rgb(238, 238, 238);
}
</style>
